#!/bin/ksh

# This file and its contents are supplied under the terms of the
# Common Development and Distribution License ("CDDL"), version 1.0.
# You may only use this file in accordance with the terms of version
# 1.0 of the CDDL.
#
# A full copy of the text of the CDDL should have accompanied this
# source. A copy of the CDDL is also available via the Internet at
# http://www.illumos.org/license/CDDL.

# Copyright 2022 OmniOS Community Edition (OmniOSce) Association.
# Copyright 2019 Joyent, Inc.

# A simple update script that extracts an Intel microcode download file
# into the intel/ directory, and updates the hardlinks in the
# system/kernel/platform manifest.

function errexit {
	echo "$@" >&2
	exit 1
}

[[ -n "$1" && -f "$1" ]] || errexit "Syntax: $0 <path to microcode tar>"

ucodetar="$1"

FW=platform/i86pc/ucode/GenuineIntel
LINKSF=intel/Makefile.links

export LC_ALL=C.UTF-8

set -e
set -o pipefail

mf=../../pkg/manifests/system-microcode-intel.p5m
[[ -f $mf ]] || errexit "Run from usr/src/data/ucode"

function find_cmd {
	typeset cmd="$1"
	typeset var=$(echo $cmd | tr '[:lower:]' '[:upper:]')
	typeset -n path="$var"
	path=$(whence -fp "$cmd")
	if (($? != 0)) || [ ! -x "$path" ]; then
		errexit "Cannot find executable '$cmd' in PATH"
	fi
}

# This script uses a few commands which are not part of illumos and are
# expected to be available in the path.
find_cmd gtar
find_cmd pkgfmt
# Search for 'ucodeadm'. If you need to use an updated ucodeadm to handle this
# firmware update, as is occasionally necessary, ensure it occurs earlier in
# the path than /usr/sbin.
find_cmd ucodeadm

tmp=$(mktemp -d)
[[ -n "$tmp" && -d "$tmp" ]]
mkdir $tmp/out || errexit "Failed to create temporary directory"
trap 'rm -rf $tmp' EXIT

# The distributed microcode archive uses GNU extensions
$GTAR -C $tmp -xvf "$ucodetar"

path=$({ cd $tmp; echo Intel-Linux-Processor-Microcode-Data*; })
ver=${path##*-}
echo "** Updating to microcode version $ver"

find $tmp/$path/intel-ucode*/ -type f | while read f; do
	echo "Converting $(basename $f)"
	cp $f $tmp/intel-fw
	$UCODEADM -i -R $tmp/out $tmp/intel-fw
	rm -f $tmp/intel-fw
done

$PKGFMT -u $mf
mv $mf $mf.tmp
egrep -v "(file|hardlink) path=$FW" $mf.tmp > $mf
rm -f $mf.tmp

rm -f intel/*-*

cp $tmp/$path/license intel/THIRDPARTYLICENSE
echo Intel Processor Microcode Data Files > intel/THIRDPARTYLICENSE.descrip

rm -f $LINKSF

typeset -A seen
typeset -A inodes
typeset -A links

for f in $tmp/out/*; do
	bf=$(basename $f)
	[[ -n "${seen[$bf]}" ]] && continue
	inode=$(stat -c %i $f)
	if [[ -n "${inodes[$inode]}" ]]; then
		links[$bf]=${inodes[$inode]}
	else
		inodes[$inode]=$bf
		cp $f intel/$bf
	fi
	seen[$bf]=1
done

for f in intel/*; do
	bf=$(basename $f)
	[[ $bf = THIRDPARTYLICENSE* ]] && continue
	[[ $bf = Makefile* ]] && continue
	echo "file path=$FW/$bf group=sys mode=0444 reboot-needed=true" >> $mf
done

(
	sed '/^$/q' < ../../prototypes/prototype.Makefile
	echo 'INTEL_LINKS = \'
	for i in "${!links[@]}"; do
		echo "\t$i \\"
	done | sed '$s/ .*//'
	echo
) > $LINKSF

for i in "${!links[@]}"; do
	echo "hardlink path=$FW/$i target=${links[$i]}" >> $mf
	cat << EOM >> $LINKSF
\$(ROOTINTELDIR)/$i: \$(ROOTINTELDIR)/${links[$i]}
	\$(RM) \$@; \$(LN) \$^ \$@

EOM
done

sed -i "/pkg.fmri.*microcode\/intel@/s/@[0-9]*/@$ver/" $mf

$PKGFMT -fv2 $mf

